package com.njust.RateMyTray_backend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njust.RateMyTray_backend.common.ForbiddenException;
import com.njust.RateMyTray_backend.common.ResourceNotFoundException;
import com.njust.RateMyTray_backend.dto.DishCreateDTO;
import com.njust.RateMyTray_backend.dto.DishUpdateDTO;
import com.njust.RateMyTray_backend.entity.Comment;
import com.njust.RateMyTray_backend.entity.Dish;
import com.njust.RateMyTray_backend.entity.DishTag;
import com.njust.RateMyTray_backend.entity.Tag;
import com.njust.RateMyTray_backend.entity.User;
import com.njust.RateMyTray_backend.entity.Window;
import com.njust.RateMyTray_backend.mapper.DishMapper;
import com.njust.RateMyTray_backend.mapper.TagMapper;
import com.njust.RateMyTray_backend.service.*;
import com.njust.RateMyTray_backend.vo.CommentVO;
import com.njust.RateMyTray_backend.vo.DishDetailVO;
import com.njust.RateMyTray_backend.vo.DishVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    @Autowired
    private WindowService windowService;

    @Autowired
    private TagMapper tagMapper;
    
    @Autowired
    private TagService tagService;
    
    @Autowired
    private DishTagService dishTagService;

    @Autowired
    private CommentService commentService;

    @Autowired
    private UserService userService;

    private final ObjectMapper objectMapper = new ObjectMapper();


    @Override //按热度返回菜品列表
    public List<DishVO> getHotDishesByWindowId(long windowId) {
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Dish::getWindowId, windowId)
                .eq(Dish::getStatus, "available")
                .orderByDesc(Dish::getPopularity)
                .last("LIMIT 10");

        List<Dish> dishes = this.list(queryWrapper);

        return dishes.stream().map(dish -> DishVO.builder()
                .dishId(dish.getId())
                .name(dish.getDishName())
                .imageUrl(dish.getImageUrl())
                .price(dish.getPrice())
                .description(dish.getDescription())
                .status(dish.getStatus())
                .build()).collect(Collectors.toList());
    }

    @Override
    public DishDetailVO getDishDetails(Long dishId) {
        // 1. 获取菜品信息
        Dish dish = this.getById(dishId);
        if (dish == null) {
            throw new ResourceNotFoundException("菜品不存在");
        }

        // 2. 获取窗口信息
        Window window = windowService.getById(dish.getWindowId());
        if (window == null) {
            throw new ResourceNotFoundException("菜品所属窗口不存在");
        }

        // 3. 获取标签
        List<String> tags = tagMapper.findTagNamesByDishId(dishId);

        // 4. 获取评价并计算平均分
        LambdaQueryWrapper<Comment> commentQuery = new LambdaQueryWrapper<>();
        commentQuery.eq(Comment::getTargetId, dishId).eq(Comment::getTargetType, "dish");
        List<Comment> comments = commentService.list(commentQuery);

        BigDecimal averageRating = comments.stream()
                .map(comment -> new BigDecimal(comment.getRating()))
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .divide(new BigDecimal(Math.max(comments.size(), 1)), 2, RoundingMode.HALF_UP);
        
        // 5. 转换评价为VO
        List<Long> userIds = comments.stream().map(Comment::getReviewerId).distinct().collect(Collectors.toList());
        Map<Long, User> userMap = userIds.isEmpty() ? Collections.emptyMap() :
                userService.listByIds(userIds).stream().collect(Collectors.toMap(User::getId, user -> user));

        List<CommentVO> commentVOs = comments.stream().map(comment -> {
            User reviewer = userMap.get(comment.getReviewerId());
            CommentVO vo = new CommentVO();
            vo.setCommentId(comment.getId());
            vo.setParentId(comment.getParentId());
            vo.setRating(comment.getRating());
            vo.setContent(comment.getContent());
            vo.setCommentTime(comment.getCommentedAt());
            vo.setHelpfulCount(comment.getHelpfulCount());
            vo.setIsOfficialReply(comment.getIsOfficialReply());
            vo.setImageUrls(parseImageUrls(comment.getImageUrls()));

            if (comment.getIsAnonymous()) {
                vo.setReviewerName("匿名用户");
                vo.setAvatarUrl(null); 
            } else if (reviewer != null) {
                vo.setReviewerName(reviewer.getNickname());
                vo.setAvatarUrl(reviewer.getAvatarUrl());
            }
            return vo;
        }).collect(Collectors.toList());


        // 6. 组装VO
        return DishDetailVO.builder()
                .dishId(dish.getId())
                .name(dish.getDishName())
                .description(dish.getDescription())
                .imageUrl(dish.getImageUrl())
                .price(dish.getPrice())
                .status(dish.getStatus())
                .popularity(dish.getPopularity())
                .windowId(window.getId())
                .windowName(window.getWindowName())
                .tags(tags)
                .averageRating(averageRating)
                .comments(commentVOs)
                .build();
    }
    
    @Transactional
    @Override
    public Dish createDish(Long windowId, Long merchantId, DishCreateDTO createDTO) {
        // 1. 验证窗口所有权
        Window window = windowService.getById(windowId);
        if (window == null) {
            throw new ResourceNotFoundException("指定的窗口不存在");
        }
        if (!window.getMerchantId().equals(merchantId)) {
            throw new ForbiddenException("无权限为该窗口添加菜品");
        }
        
        // 2. 创建并保存菜品基本信息
        Dish newDish = new Dish();
        newDish.setWindowId(windowId);
        newDish.setDishName(createDTO.getName());
        newDish.setDescription(createDTO.getDescription());
        newDish.setPrice(createDTO.getPrice());
        newDish.setImageUrl(createDTO.getImageUrl());
        newDish.setStatus("pending"); // 使用更短的状态名 "pending"
        this.save(newDish);
        
        // 3. 处理标签
        if (!CollectionUtils.isEmpty(createDTO.getTags())) {
            List<DishTag> dishTags = createDTO.getTags().stream().map(tagName -> {
                // 查找或创建标签
                Tag tag = tagService.lambdaQuery().eq(Tag::getTagName, tagName).one();
                if (tag == null) {
                    tag = new Tag();
                    tag.setTagName(tagName);
                    tag.setCategory("default"); // 默认分类
                    tagService.save(tag);
                }
                // 创建关联关系
                return new DishTag(newDish.getId(), tag.getId());
            }).collect(Collectors.toList());
            
            // 批量保存关联关系
            dishTagService.saveBatch(dishTags);
        }
        
        return newDish;
    }

    @Transactional
    @Override
    public void updateDishByMerchant(Long dishId, Long merchantId, DishUpdateDTO updateDTO) {
        validateDishOwnership(dishId, merchantId);
        Dish dish = this.getById(dishId); // 重新获取以确保安全

        // 2. 更新菜品基本信息
        if (StringUtils.hasText(updateDTO.getName())) dish.setDishName(updateDTO.getName());
        if (updateDTO.getDescription() != null) dish.setDescription(updateDTO.getDescription());
        if (updateDTO.getPrice() != null) dish.setPrice(updateDTO.getPrice());
        if (updateDTO.getImageUrl() != null) dish.setImageUrl(updateDTO.getImageUrl());
        if (StringUtils.hasText(updateDTO.getStatus())) dish.setStatus(updateDTO.getStatus());
        
        // 任何修改都需要重新审核
        dish.setStatus("pending");
        this.updateById(dish);

        // 3. 更新标签 (先删后增)
        if (updateDTO.getTags() != null) {
            // 删除旧的标签关联
            dishTagService.lambdaUpdate().eq(DishTag::getDishId, dishId).remove();
            
            if (!CollectionUtils.isEmpty(updateDTO.getTags())) {
                 List<DishTag> dishTags = updateDTO.getTags().stream().map(tagName -> {
                    Tag tag = tagService.lambdaQuery().eq(Tag::getTagName, tagName).one();
                    if (tag == null) {
                        tag = new Tag();
                        tag.setTagName(tagName);
                        tag.setCategory("default");
                        tagService.save(tag);
                    }
                    return new DishTag(dishId, tag.getId());
                }).collect(Collectors.toList());
                dishTagService.saveBatch(dishTags);
            }
        }
    }

    @Transactional
    @Override
    public void deleteDishByMerchant(Long dishId, Long merchantId) {
        validateDishOwnership(dishId, merchantId);

        // 2. 删除标签关联
        dishTagService.lambdaUpdate().eq(DishTag::getDishId, dishId).remove();
        
        // 3. 删除菜品本身
        this.removeById(dishId);
    }

    @Override //审核菜品
    public void auditDish(Long dishId, String status) {
        Dish dish = this.getById(dishId);
        if (dish == null) {
            throw new ResourceNotFoundException("菜品不存在");
        }

        if (!"pending".equals(dish.getStatus())) {
            throw new ForbiddenException("该菜品不是待审核状态");
        }

        if ("approved".equals(status)) {
            dish.setStatus("available");
        } else if ("rejected".equals(status)) {
            dish.setStatus("unavailable");
        } else {
            throw new ForbiddenException("无效的审核状态");
        }

        this.updateById(dish);
    }

    @Override //根据标签分类返回菜品列表
    public List<DishVO> getDishesByTag(List<String> tagNames) {
        if (tagNames == null || tagNames.isEmpty()) {
            return Collections.emptyList();
        }
        List<String> distinctTagNames = tagNames.stream().distinct().collect(Collectors.toList());
        int tagCount = distinctTagNames.size();
        if (tagCount == 0) {
            return Collections.emptyList();
        }

        List<Dish> dishes = baseMapper.findDishesByTagNames(distinctTagNames, tagCount);
        return dishes.stream().map(dish -> DishVO.builder()
                .dishId(dish.getId())
                .name(dish.getDishName())
                .imageUrl(dish.getImageUrl())
                .price(dish.getPrice())
                .description(dish.getDescription())
                .status(dish.getStatus())
                .build()).collect(Collectors.toList());
    }

    @Override //获取待审核菜品列表
    public List<DishVO> getPendingDishes() {
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Dish::getStatus, "pending");
        List<Dish> dishes = this.list(queryWrapper);

        return dishes.stream().map(dish -> DishVO.builder()
                .dishId(dish.getId())
                .name(dish.getDishName())
                .imageUrl(dish.getImageUrl())
                .price(dish.getPrice())
                .description(dish.getDescription())
                .status(dish.getStatus())
                .build()).collect(Collectors.toList());
    }

    //验证菜品所有权
    private void validateDishOwnership(Long dishId, Long merchantId) {
        Dish dish = this.getById(dishId);
        if (dish == null) {
            throw new ResourceNotFoundException("菜品不存在");
        }
        Window window = windowService.getById(dish.getWindowId());
        if (window == null || !window.getMerchantId().equals(merchantId)) {
            throw new ForbiddenException("无权限操作此菜品");
        }
    }

    //解析图片URL列表
    private List<String> parseImageUrls(String json) {
        if (!StringUtils.hasText(json)) {
            return Collections.emptyList();
        }
        try {
            return objectMapper.readValue(json, new TypeReference<List<String>>() {});
        } catch (JsonProcessingException e) {
            // log.error("解析图片URL列表JSON失败: {}", json, e);
            return Collections.emptyList();
        }
    }
} 